﻿using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.UI;
using BRMC.IntelligentCommunity.IntelligentCommunity.Parkings;
using BRMC.IntelligentCommunity.IntelligentCommunity.Sys;
using BRMC.IntelligentCommunity.IntelligentCommunity.Users;
using BRMC.IntelligentCommunity.Parkings.ParkGuards.Dto;
using BRMC.IntelligentCommunity.Parkings.Places.Dto;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BRMC.IntelligentCommunity.Parkings
{
    public class PlacesAppService : AsyncCrudAppService<
            Place,
           PlaceListDto,
            long,
             GetPlaceInput,
            CreatePlaceDto,
            UpdatePlace
            >
    {
        private readonly IRepository<Parking, long> _parking;
        private readonly IRepository<Place, long> _repository;
        private readonly IRepository<UserParkinginfo, long> _userParkinginforepository;
        private readonly IRepository<CarInfo, long> _carInforepository;
        private readonly IRepository<Paymethod, long> _paymethodRepository;
        private readonly IRepository<User_base_info, long> _user_base_info;
        private readonly IRepository<Sys_house_info> _sys_house_info;  //sys_neighbourhood_info
        private readonly IRepository<User_house_info> _user_house_info;
        private readonly IRepository<Sys_neighbourhood_info> _sys_neighbourhood_info;
        private readonly IRepository<UserCarInfo, long> _userCarInfoRepository;
        public PlacesAppService(IRepository<Place, long> repository,
            IRepository<Parking, long> parking,
            IRepository<UserParkinginfo, long> userParkinginforepository,
             IRepository<User_base_info, long> user_base_info,
              IRepository<Sys_house_info> sys_house_info,
              IRepository<User_house_info> user_house_info,
              IRepository<Sys_neighbourhood_info> sys_neighbourhood_info,
              IRepository<CarInfo, long> carInforepository,
               IRepository<Paymethod, long> paymethodRepository,
               IRepository<UserCarInfo, long> userCarInfoRepository
            ) : base(repository)
        {
            _parking = parking;
            _repository = repository;
            _userParkinginforepository = userParkinginforepository;
            _user_base_info = user_base_info;
            _sys_house_info = sys_house_info;
            _user_house_info = user_house_info;
            _sys_neighbourhood_info = sys_neighbourhood_info;
            _carInforepository = carInforepository;
            _paymethodRepository = paymethodRepository;
            _userCarInfoRepository = userCarInfoRepository;
        }
        protected override IQueryable<Place> CreateFilteredQuery(GetPlaceInput input)
        {
            return base.CreateFilteredQuery(input)
                .Where(c => c.ParkingId == input.ParkingId);

        }

        public override Task<PlaceListDto> Create(CreatePlaceDto input)
        {
            var parking = _parking.FirstOrDefault(c => c.Id == input.ParkingId);
            parking.PlaceCount = parking.PlaceCount + 1;

            return base.Create(input);

        }
        public override Task Delete(EntityDto<long> input)
        {

            var place = _repository.GetAsync(input.Id).Result;
            var parking = _parking.FirstOrDefault(c => c.Id == place.ParkingId);

            if (parking.PlaceCount > 1)
            {
                parking.PlaceCount = parking.PlaceCount - 1;
            }

            return base.Delete(input);
        }

        public async Task<GetPlaceForEditOutput> GetPlaceForEdit(NullableIdDto input)
        {
            Place place = null;
            if (input.Id.HasValue)
            {
                place = await _repository.GetAsync(input.Id.Value);
            }
            var output = new GetPlaceForEditOutput();
            output.PlaceEdit = place != null ? ObjectMapper.Map<PlaceEditDto>(place) : new PlaceEditDto();
            return output;
        }

        public async Task<UserParkingInfo> GetUserParkingInfo(string phoneNumber)
        {
            var user = await _user_base_info.FirstOrDefaultAsync(c => c.Phone == phoneNumber);
            var user_house_info = await _user_house_info.FirstOrDefaultAsync(c => c.Userid == user.Id);
            var sys_house_info = await _sys_house_info.FirstOrDefaultAsync(c => c.Id == user_house_info.Houseid);
            var neighbourhood = await _sys_neighbourhood_info.FirstOrDefaultAsync(c => c.Id == sys_house_info.Neighbourhood_id);
            // var carsinfo = _carInforepository.GetAll().GroupBy(c => c.Id).Select{ o=>new {carid=o.key}}



            var carsinfo = _carInforepository.GetAll().GroupBy(c => c.Id).Select(o => new { CarId = o.Key });
            //var userParkings = await _userParkinginforepository.GetAllListAsync(c => c.UserBaseInfoId == user.Id);
            var userPlaceList = new List<UserPlaceListDto>();
            var userParkings = _userParkinginforepository.GetAll().Where(c => c.UserBaseInfoId == user.Id).GroupBy(c => c.PlaceId)
            .Select(c => new
            {
                placesId = c.Key,
                Cars = c.Where(x => x.PlaceId == c.Key).Select(o => new { carid = o.CarId })

            }).ToList();


            foreach (var item in userParkings)
            {
                var place = _repository.FirstOrDefault(c => c.Id == item.placesId);
                if (place != null)
                {
                    var carsNums = new List<CarInfoDto>();
                    foreach (var item1 in item.Cars)
                    {
                        if (item1.carid != null)
                        {
                            var carinfo = _carInforepository.FirstOrDefault(c => c.Id == item1.carid);
                            carsNums.Add(new CarInfoDto() { Id = carinfo.Id, CarNum = carinfo.CarNum});
                        }
                    }
                    var userPlace = new UserPlaceListDto()
                    {
                        ParkingId = place.ParkingId,
                        ParkingName = place.ParkingName,
                        ParkingCode = place.ParkingCode,
                        PlaceNo = place.PlaceNo,
                        PlaceName = place.PlaceName,
                        PlaceSatus = place.PlaceSatus,
                        Remark = place.Remark,
                        TenantId = place.TenantId,
                        Neighbourhood_id = place.Neighbourhood_id,
                        Neighbourhood_name = place.Neighbourhood_name,
                        EndTime = place.EndTime,
                        CarNums = carsNums,
                        PlaceId = item.placesId

                    };
                    userPlaceList.Add(userPlace);
                }


            }




            var userParkingInfo = new UserParkingInfo()

            {
                UserId = user.Id,
                Name = user.Name,
                Phone = user.Phone,
                NeighbourhoodName = neighbourhood.Name,
                Address = sys_house_info.All,
                placeListDtos = userPlaceList
            };

            return userParkingInfo;
        }

        /// <summary>
        /// 车位中增加车辆
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UserPakingForNewLicense(GetUserParkingInfoForEditOutput input)
        {
            //获取车辆信息
            var carInfo = await _carInforepository.FirstOrDefaultAsync(e => e.CarNum == input.CarInfo.CarNum);
            if (carInfo == null)
            {
                input.CarInfo.Id = await _carInforepository.InsertAndGetIdAsync(ObjectMapper.Map<CarInfo>(input.CarInfo));
            }
            else 
            {
                input.CarInfo.Id = carInfo.Id;
            }

            //当前车辆是否在当前车位
            if (_userParkinginforepository.GetAll().Any(e => e.CarId == input.CarInfo.Id && e.PlaceId == input.PlacesId))
            {
                throw new UserFriendlyException("当前车辆已在当前车位注册");
            }

            //当前车位插入当前车辆信息
            var userParkinginfo = await _userParkinginforepository.FirstOrDefaultAsync(c => c.Id == input.PlacesId && c.CarId == null);
            var place = await _repository.FirstOrDefaultAsync(c => c.Id == input.PlacesId);
            if (userParkinginfo == null)
            {
                
                var userParkingLast = await _userParkinginforepository.GetAll().OrderByDescending(e => e.Id).FirstOrDefaultAsync(e => e.UserBaseInfoId == input.UserId && e.PlaceId == input.PlacesId);
                var userParkingInfo = new UserParkinginfoDto()
                {
                    UserBaseInfoId = input.UserId,
                    PlaceId = input.PlacesId,
                    CarId = input.CarInfo.Id,
                    Neighbourhood_id = place.Neighbourhood_id,
                    Neighbourhood_name = place.Neighbourhood_name,
                    ParkingCode = place.ParkingCode,
                    ParkingName = place.ParkingName,
                    ParkingId = place.ParkingId
                };

                var userParking = ObjectMapper.Map<UserParkinginfo>(userParkingInfo);
                userParking.StartTime = userParkingLast?.StartTime;
                userParking.EndTime = place.EndTime;
                await _userParkinginforepository.InsertAsync(userParking);
            }
            else
            {
                userParkinginfo.CarId = input.CarInfo.Id;
                await _userParkinginforepository.UpdateAsync(userParkinginfo);
            }

            //车辆与人员表中如果不存在，插入
            var userCarAny = await _userCarInfoRepository.GetAll().AnyAsync(e => e.UserBaseInfoId == input.UserId && e.CarId == input.CarInfo.Id);
            if (!userCarAny)
            {
                var userCar = new UserCarInfo()
                {
                    UserBaseInfoId = input.UserId,
                    CarId = input.CarInfo.Id,
                    ParkingId = place.ParkingId,
                    Neighbourhood_id = place.Neighbourhood_id,
                    TenantId = place.TenantId
                };
                await _userCarInfoRepository.InsertAsync(userCar);
            }

            /*
            var carinfo = input.CarInfo;

            var car = ObjectMapper.Map<CarInfo>(carinfo);
      var cars=      await _carInforepository.GetAllListAsync();

            foreach (var item in cars)
            {
                if (item.CarNum == car.CarNum)
                {
                    throw new  UserFriendlyException("当前车牌已注册");
                }
            }
            var carId = await _carInforepository.InsertAndGetIdAsync(car);

            var place = await _repository.FirstOrDefaultAsync(c => c.Id == input.PlacesId);

            var userParkinginfo = await _userParkinginforepository.FirstOrDefaultAsync(c => c.Id == input.PlacesId && c.CarId == null);
            if (userParkinginfo == null)
            {
                var userParkingInfo = new UserParkinginfoDto()
                {
                    UserBaseInfoId = input.UserId,
                    PlaceId = input.PlacesId,
                    CarId = carId,
                    Neighbourhood_id = place.Neighbourhood_id,
                    Neighbourhood_name = place.Neighbourhood_name,
                    ParkingCode = place.ParkingCode,
                    ParkingName = place.ParkingName,
                    ParkingId = place.ParkingId
                };

                var userParking = ObjectMapper.Map<UserParkinginfo>(userParkingInfo);
                await _userParkinginforepository.InsertAsync(userParking);
            }
            else
            {
                userParkinginfo.CarId = carId;
                await _userParkinginforepository.UpdateAsync(userParkinginfo);
            }

           */

        }

        /// <summary>
        /// 车位续费
        /// </summary>
        /// <param name="placeId"></param>
        /// <param name="userbaseInfoId"></param>
        /// <param name="cycle">续费月数</param>
        /// <param name="cost">续费金额</param>
        /// <returns></returns>
        public async Task UpdateEndTime(long placeId,long userbaseInfoId, int cycle, decimal cost)
        {
            var place = await _repository.FirstOrDefaultAsync(placeId);
            if (place == null)
            {
                throw new UserFriendlyException("未找到车位信息，续费失败");
            }
            if (!place.EndTime.HasValue)
            {
                throw new UserFriendlyException("没有交费信息，续费失败");
            }

            place.EndTime = place.EndTime.Value.AddMonths(cycle);
            await _repository.UpdateAsync(place);

            var userParkingList = await _userParkinginforepository.GetAll().Where(e => e.PlaceId == placeId && e.UserBaseInfoId == userbaseInfoId).ToListAsync();
            if (userParkingList.Count == 0)
            {
                throw new UserFriendlyException("未找到该用户车位信息，续费失败");
            }
            foreach (var userParking in userParkingList)
            {
                userParking.EndTime = place.EndTime;
                await _userParkinginforepository.UpdateAsync(userParking);
            }
            //await _userParkinginforepository.BulkUpdateAsync(userParkingList);

            var paymethod = new Paymethod()
            {
                Cost = cost,
                Cycle = cycle,
                Neighbourhood_id = place.Neighbourhood_id,
                ParkingId = place.ParkingId,
                PlaceId = placeId,
                UserId = userbaseInfoId
            };
            await _paymethodRepository.InsertAsync(paymethod);
        }



        public async Task<ListResultDto<ComboboxItemDto>> GetComboxForPlaces()
        {
            var query = _repository.GetAll().Where(c => c.IsRent == 0).Select(e => new ComboboxItemDto(e.Id.ToString(), e.PlaceName)).ToList();
            return new ListResultDto<ComboboxItemDto>(query);
        }


        public async Task SetUserParkings(SetUserParkingInput input)
        {
            DateTime? startTime = null;
            DateTime? endTime = null;
            if (input.STime.HasValue)
            {
                startTime = Convert.ToDateTime(input.STime.Value.ToString("yyyy-MM-dd"));
            }
            if (input.Etime.HasValue)
            {
                endTime = Convert.ToDateTime(input.Etime.Value.AddDays(1).ToString("yyyy-MM-dd")).AddSeconds(-1);
            }

            var place = await _repository.FirstOrDefaultAsync(input.PlacesId);
            if (place == null)
            {
                throw new UserFriendlyException("保存失败！未找到车位信息");
            }
            if (place.IsRent == 1)
            {
                throw new UserFriendlyException("保存失败！车位已出租/售出");
            }
            place.IsRent = 1;
            place.EndTime = endTime;
            await _repository.UpdateAsync(place);

            var car = await _carInforepository.GetAll().FirstOrDefaultAsync(e => e.CarNum == input.CarNum);
            if (input.Checked)
            {
                if (car == null)
                {
                    car = new CarInfo();
                    car.CarNum = input.CarNum;
                    car.CarType = 2 ;
                    car.LicenseColor = input.CarType;
                    car.VehicleBrand = input.CarInfo;
                    car.Neighbourhood_id = place.Neighbourhood_id;
                    car.Neighbourhood_name = place.Neighbourhood_name;
                    car.ParkingCode = place.ParkingCode;
                    car.ParkingId = place.ParkingId;
                    car.ParkingName = place.ParkingName;

                    var carId = await _carInforepository.InsertAndGetIdAsync(car);
                    car.Id = carId;
                }

                var userCarAny = await _userCarInfoRepository.GetAll().AnyAsync(e=>e.UserBaseInfoId == input.UserId && e.CarId == car.Id);
                if (!userCarAny)
                {
                    var userCar = new UserCarInfo()
                    {
                        UserBaseInfoId = input.UserId,
                        Neighbourhood_id = place.Neighbourhood_id,
                        ParkingId = place.ParkingId,
                        TenantId = place.TenantId,
                        CarId = car.Id
                    };
                    await _userCarInfoRepository.InsertAsync(userCar);
                }
            }

            var userParking = new UserParkinginfo()
            {
                UserBaseInfoId = input.UserId,
                PlaceId = place.Id,
                Neighbourhood_id = place.Neighbourhood_id,
                Neighbourhood_name = place.Neighbourhood_name,
                ParkingId = place.ParkingId,
                ParkingCode = place.ParkingCode,
                ParkingName = place.ParkingName,
                StartTime = startTime,
                EndTime = endTime
            };
            if (input.Checked == true && car != null)
            {
                userParking.CarId = car.Id;
            }
            await _userParkinginforepository.InsertAsync(userParking);

            var paymethod = new Paymethod()
            {
                Cost = input.Cost,
                PlaceId = place.Id,
                ParkingId = place.ParkingId,
                UserId = input.UserId,
                Neighbourhood_id = place.Neighbourhood_id,
                Cycle = input.Cycle
            };
            await _paymethodRepository.InsertAsync(paymethod);


            #region
            /*
            //购买时不增加车辆
            if (input.Checked == false)
            {

                var place = await _repository.FirstOrDefaultAsync(c => c.Id == input.PlacesId);
                place.IsRent = 1;
                place.EndTime = endTime;
                await _repository.UpdateAsync(place);

                var userParking = new UserParkinginfo()
                {
                    UserBaseInfoId = input.UserId,
                    PlaceId = place.Id,
                    Neighbourhood_id = place.Neighbourhood_id,
                    Neighbourhood_name = place.Neighbourhood_name,
                    ParkingId = place.ParkingId,
                    ParkingCode = place.ParkingCode,
                    ParkingName = place.ParkingName,
                    StartTime = startTime,
                    EndTime = endTime 
                };
                await _userParkinginforepository.InsertAsync(userParking);

                var paymethod = new Paymethod()
                {
                    Cost = input.Cost,
                    PlaceId = place.Id,
                    ParkingId = place.ParkingId,
                    UserId = input.UserId,
                    Neighbourhood_id = place.Neighbourhood_id,
                    Cycle = input.Cycle
                };

                await _paymethodRepository.InsertAsync(paymethod);
            }

            if (input.Checked == true)
            {

                var place = await _repository.FirstOrDefaultAsync(c => c.Id == input.PlacesId);
                place.IsRent = 1;
                place.EndTime = input.Etime;
                await _repository.UpdateAsync(place);
                var car = new CarInfo();

                car.CarNum = input.CarNum;
                car.CarType = input.Checked2 == true ? 2 : 3;
                car.LicenseColor = input.CarType;
                car.VehicleBrand = input.CarInfo;
                car.Neighbourhood_id = place.Neighbourhood_id;
                car.Neighbourhood_name = place.Neighbourhood_name;
                car.ParkingCode = place.ParkingCode;
                car.ParkingId = place.ParkingId;
                car.ParkingName = place.ParkingName;


                var carId = await _carInforepository.InsertAndGetIdAsync(car);


                var userParking = new UserParkinginfo()
                {
                    UserBaseInfoId = input.UserId,
                    PlaceId = place.Id,
                    Neighbourhood_id = place.Neighbourhood_id,
                    Neighbourhood_name = place.Neighbourhood_name,
                    ParkingId = place.ParkingId,
                    ParkingCode = place.ParkingCode,
                    ParkingName = place.ParkingName,
                    CarId = carId,
                    StartTime = startTime,
                    EndTime = endTime
                };
                await _userParkinginforepository.InsertAsync(userParking);

                var paymethod = new Paymethod()
                {
                    Cost = input.Cost,
                    PlaceId = place.Id,
                    ParkingId = place.ParkingId,
                    UserId = input.UserId,
                    Neighbourhood_id = place.Neighbourhood_id,
                    Cycle = input.Cycle
                };

                await _paymethodRepository.InsertAsync(paymethod);
            }
            */
            #endregion
        }

        /// <summary>
        /// 根据手机号判断该用户是否有车位信息
        /// </summary>
        /// <param name="phone"></param>
        /// <returns>返回为空时有车位信息，否则返回对应错误信息</returns>
        public async Task<string> GetPlaceInfoByPhone(string phone)
        {
            try
            {
                var result = "";
                if (phone == null || phone == "")
                {
                    result = "请输入手机号码";
                    return result;
                }

                var user_base_Info = await this._user_base_info.FirstOrDefaultAsync(e => e.Phone == phone);
                if (user_base_Info == null)
                {
                    result = "未找到手机号为" + phone + "用户信息";
                    return result;
                }

                return result;
            }
            catch (Exception e) {
                throw e;
            }
        }

        /// <summary>
        /// 删除车位中车辆信息
        /// </summary>
        /// <param name="carId"></param>
        /// <param name="placeId"></param>
        /// <returns></returns>
        public async Task DeleteUserParkingInfo(long carId, long placeId)
        {
            var userParkingInfo = await _userParkinginforepository.FirstOrDefaultAsync(e => e.CarId == carId && e.PlaceId == placeId);
            if (userParkingInfo != null)
            {
                await _userParkinginforepository.DeleteAsync(userParkingInfo.Id);
            }
        }

        /// <summary>
        /// 获取车位租售信息
        /// </summary>
        /// <param name="placeId"></param>
        /// <returns></returns>
        public async Task<PlaceUserDto> GetPlacsUser(long placeId)
        {
            var place = await _repository.FirstOrDefaultAsync(placeId);
            var parking = await _parking.FirstOrDefaultAsync(place.ParkingId);

            var userParkingInfoList = await _userParkinginforepository.GetAll().Where(e => e.PlaceId == placeId)
                .Select(e => new {
                    UserBaseInfoId = e.UserBaseInfoId,
                    CarId = e.CarId,
                    CreationTime = e.CreationTime
                }).ToListAsync();

            var userBaseInfo = new User_base_info();
            var carNunms = "";
            if (userParkingInfoList.Count > 0)
            {
                userBaseInfo = await _user_base_info.FirstOrDefaultAsync(userParkingInfoList.OrderByDescending(e => e.CreationTime).FirstOrDefault().UserBaseInfoId);
                var carIds = userParkingInfoList.Where(e => e.CarId != null).Select(e => e.CarId).ToList();
                var carNumList = await _carInforepository.GetAll().Where(e => carIds.Contains(e.Id)).Select(e => e.CarNum).ToListAsync();
                if (carNumList.Count > 0)
                {
                    carNunms = string.Join("," , carNumList);
                }
            }

            var plaseUser = new PlaceUserDto
            {
                PlaceName = place.PlaceName,
                PlaceNum = place.PlaceNo,
                ParkingName = parking.ParkingName,
                PlaceEndDate = place.EndTime == null ? "" : place.EndTime.Value.ToString("yyyy-MM-dd"),
                UserName = userBaseInfo == null ? "" : (userBaseInfo.Name??""),
                UserPhone = userBaseInfo == null ? "" : userBaseInfo.Phone,
                CarNums = carNunms
            };

            return plaseUser;
        }

        /// <summary>
        /// 解除车位与用户的绑定（已到期的车位）
        /// </summary>
        /// <param name="placeId"></param>
        /// <returns></returns>
        public async Task<string> DeleteUserParingInfoByPlaceIdAndEndTime(long placeId)
        {
            var place = await _repository.FirstOrDefaultAsync(placeId);
            if (place == null)
            {
                return "未找到车位信息";
            }
            if (place.EndTime > DateTime.Today)
            {
                return "车位未到期，不能解除绑定";
            }

            place.IsRent = 0;
            place.EndTime = null;
            await _repository.UpdateAsync(place);

            var userParkingList = await _userParkinginforepository.GetAll().Where(e => e.PlaceId == placeId).ToListAsync();
            
            foreach (var userParking in userParkingList)
            {
                await  _userParkinginforepository.DeleteAsync(userParking);
            }

            return "";
        }
    }
}
